<template>
  <div id="center" @mousemove="mousemove">
    <!--父盒子-->
    <div
      v-for="(item, index) in mapList"
      :key="item.id"
      :id="item.id"
      :style="{
        position: 'absolute',
        left: item.x + 'px',
        top: item.y - 50 + 'px',
      }"
      @contextmenu.prevent="onContextmenu($event, item, index)"
      @dblclick="dbBtn(item)"
      name="box"
    >
      <el-button :icon="item.icon" size="mini">{{ item.name }}</el-button>
    </div>

    <!--弹窗-->
    <el-drawer
      title="子组件"
      :visible.sync="drawer"
      direction="rtl"
      id="drawer"
    >
      <el-form
        ref="form"
        :model="visibleList"
        label-width="80px"
        label-position="top"
      >
        <el-form-item label="名称">
          <el-input v-model="visibleList.name" size="small"></el-input>
        </el-form-item>
        <el-form-item label="ID">
          <el-input v-model="visibleList.id" size="small" disabled></el-input>
        </el-form-item>
        <el-form-item label="X轴">
          <el-input v-model="visibleList.x" size="small" disabled></el-input>
        </el-form-item>
        <el-form-item label="Y轴">
          <el-input v-model="visibleList.y" size="small" disabled></el-input>
        </el-form-item>
        <el-form-item label="图标">
          <el-input v-model="visibleList.icon" size="small" disabled></el-input>
        </el-form-item>
        <el-form-item id="footer">
          <el-button type="primary" @click="submitForm" size="small"
            >确定</el-button
          >
          <el-button size="small" @click="drawer = false">关闭</el-button>
        </el-form-item>
      </el-form>
    </el-drawer>
  </div>
</template>

<script>
export default {
  data() {
    return {
      drawer: false, //弹窗状态
      visibleList: {}, //弹窗数据
      mapList: [], //节点数组 --x轴--y轴--id--form表单
      connectList: [], //节点连接数组--开始-结束
      isDelete: false, //是否为删除操作
    };
  },
  created() {},
  mounted() {
    this.$nextTick(() => {
      this.creatdJplumb();
    });
  },
  methods: {
    //初始化jsPumb
    creatdJplumb() {
      this.jsplumb = this.$jsplumb.getInstance({
        PaintStyle: { stroke: "#56A7F9", strokeWidth: 2 }, //连接线的默认样式
        HoverPaintStyle: { stroke: "#13E0F9", strokeWidth: 2 }, //鼠标滑过连线样式
        Endpoint: ["Dot", { radius: 1 }], //连线终端点类型
        EndpointStyle: {
          fill: "transparent", //端点背景色
          outlineWidth: 1, //端点宽度
          outlineStroke: "transparent", //端点边框线
          radius: 5, //圆角
        }, //这个是控制连线终端那个小点的样式
        EndpointHoverStyle: { fill: "#fff", outlineStroke: "#13E0F9" }, //这个是控制鼠标滑过连线终端那个小点的样式
        Connector: ["Straight"], //连接线的样式种类有[Bezier],[Flowchart],[StateMachine ],[Straight]
        ConnectionOverlays: [
          ["Arrow", { location: 1, width: 11, length: 11, foldback: 0.618 }], //连线设置箭头

          [
            "Label",
            {
              //连线上设置label
              location: 0.5, //文字距离两端的位置
              label: "", //label显示文字-线上的文字
              id: "label", //连接线的id
              cssClass: "aLabel", //连接线的class
              events: {
                //label点击事件
                // tap: function () {
                //   alert("hey");
                // },
              },
            },
          ],
        ],
        Container: "center", //可拖动区域 ID
        DrapOptions: { cursor: "crosshair", zIndex: 2000 },
      });

      const ins = this.jsplumb; // 实例已经创建成功
      ins.getAllConnections(); //配置重新生效--重置--防止渲染失败
      ins.batch(() => {
        //渲染成功后执行
        this.initAll(); //初始化节点
        this.connectionAll(); //初始化连线
      });
      //所有要做的操作的钩子函数要在这里定义实例执行
      //建立连接---连接成功后的操作
      ins.bind("connection", this.connection);
      //建立连接前---连接前的操作--一般用来判断是否可连接
      ins.bind("beforeDrop", this.beforeDrop);
      //连线变更---移动连线的操作
      ins.bind("connectionMoved", this.connectionMoved);
      //连线断开时的操作
      ins.bind("connectionDetached", this.beforeDetach);
      //双击
      ins.bind("click", this.dblclick);
      this.switchContainer(true, true, true); //允许是否可拖拽、端点是否可用(原点是否可用、终点是否可用、是否可拖拽)
    },

    //初始化所有节点
    initAll() {
      const list = this.mapList;
      for (let row of list) {
        this.init(row);
      }
    },

    // 初始化规则使其可以连线
    init(row) {
      const ins = this.jsplumb;
      const elem = document.getElementById(row.id); //获取节点
      let common = {
        isSource: true, //是否可以作为原点
        isTarget: true, //是否可以作为目标
      };
      let direction = ["Left", "Right", "Top", "Bottom"]; //方向数组
      for (let item of direction) {
        //设置端点
        ins.addEndpoint(
          elem,
          {
            anchor: item,
            allowLoopback: false,
            maxConnections: -1, //连接线数量限制, -1则不限制数量
          },
          common
        );
      }
    },

    //建立连线
    connectionAll() {
      const ins = this.jsplumb;
      ins.ready(() => {
        for (let item of this.connectList) {
          ins.connect({
            source: item.sourceNodeId, //开始节点
            target: item.targetNodeId, //结束节点
            anchor: ["Left", "Right", "Top", "Bottom"], //圆点连接方向 这个地方可以动态生成，方向可以存储在你的连线数组内，然后动态赋值
          });
        }
      });
    },

    //初始化使其可以拖拽
    switchContainer(target, source, draggable) {
      const elem = document.getElementsByName("box"); //获取要生成拖拽实例的节点
      const ins = this.jsplumb; //获取jsplumb实例
      ins.ready(() => {
        let draggables = {
          containment: "center",
          drug: (event) => {
            window.event
              ? (window.event.cancelBubble = true)
              : event.stopPropagation();
            return false;
          },
          stop: (event) => {
            //拖拽结束
            let elem = event.el.id; // 当前拖拽节点的id
            let list = JSON.parse(JSON.stringify(this.mapList));
            for (let row of list) {
              if (elem == row.id) {
                Object.assign(row, {
                  x: event.pos[0], //拖拽之后改变x轴的位置
                  y: event.pos[1] + 50, //拖拽之后改变y轴位置
                });
              }
            }
            this.mapList = JSON.parse(JSON.stringify(list));
            window.event
              ? (window.event.cancelBubble = true)
              : event.stopPropagation();
            return false;
          },
        };
        ins.setSourceEnabled(elem, source); //设置是否允许从源目标拖出连线
        ins.setTargetEnabled(elem, target); //设置是否可从终点目标拖出连线
        ins.draggable(elem, draggable ? draggables : false); // 节点是否支持拖拽
      });
    },

    //建立连接之后的事件
    connection(connt) {
      //connt.endpoints[0].anchor.anchors[0].type; 可获取源点锚点方向
      //connt.endpoints[1].anchor.anchors[0].type; 可获取终点锚点方向
      console.log("建立连接后", connt); //connt包含sourceId ，targetId 等值; sourceId为源目标的id，targetId为你要连接的元素的id
      //你可以通过id来获取你想要的元素
      let list = JSON.parse(JSON.stringify(this.connectList));
      let isConnt = list.filter(
        (x) =>
          x.sourceNodeId == connt.sourceId && x.targetNodeId == connt.targetId
      );
      if (isConnt || isConnt.length == 0) {
        list.push({
          sourceNodeId: connt.sourceId,
          targetNodeId: connt.targetId,
          // startAnchor: connt.endpoints[0].anchor.anchors[0].type, //源点锚点方向
          // endAnchor: connt.endpoints[1].anchor.anchors[0].type, //终点锚点方向
        });
      }
      this.connectList = JSON.parse(JSON.stringify(list));
      console.log(this.connectList);
    },

    //连线移动或者变更事件
    connectionMoved(connt) {
      // 这里返回的是连线前的id
      let sourceId = connt.originalSourceId; //移动前的源目标id id可根据自己设置的id变更 node是我设置的id
      let targetId = connt.originalTargetId; //移动前的目标id
      //将移动之前的连线记录清空
      for (let index in this.connectList) {
        if (
          this.connectList[index].sourceNodeId == sourceId &&
          this.connectList[index].targetNodeId == targetId
        ) {
          this.connectList.splice(index, 1);
          return false;
        }
      }
      console.log("变更");
      console.log(this.connectList);
    },

    //建立连接前
    beforeDrop(connt) {
      // alert("建立连接前");
      console.log("连接前", connt); //connt包含sourceId ，targetId 等值; sourceId为源目标的id，targetId为你要连接的元素的id
      return true; //true为允许连接，false为不允许连接
    },

    //连接断开前的操作
    beforeDetach(connt) {
      console.log("连接断开", connt);
      // if (this.isDelete) {
      //将移动之前的连线记录清空
      for (let index in this.connectList) {
        if (
          this.connectList[index].sourceNodeId == connt.sourceId &&
          this.connectList[index].targetNodeId == connt.targetId
        ) {
          this.connectList.splice(index, 1);
          return false;
        }
      }
      this.$nextTick(() => {
        this.connectionAll();
      });
      // }
      // return true;
    },

    //双击
    dblclick(connt, orignEvent) {
      console.log("双击");
      console.log(connt);
      window.event
        ? (window.event.cancelBubble = true)
        : orignEvent.stopPropagation();
      let messageBox = document.querySelector("body .el-message-box__wrapper");
      if (messageBox) return false;
      this.$confirm("确定删除所点击的线吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          // let elem = this.jsplumb.getAllConnections({
          //   source: connt.sourceId,
          //   target: connt.targetId,
          // })[0];
          // this.jsplumb.deleteEveryConnection(elem);
          setTimeout(() => {
            this.jsplumb.deleteConnection(connt);
          }, 100);
          document.querySelector("body .el-message-box__wrapper").remove();
          return false;
        })
        .catch(() => {});
      return false;
    },

    // 右键菜单
    onContextmenu(event, item, index) {
      this.isDelete = false;
      console.log(event, item, index);
      console.log(item);
      this.$contextmenu({
        items: [
          {
            label: "删除",
            onClick: () => {
              this.isDelete = true;
              this.mapList.splice(index, 1);
              this.jsplumb.remove(item.id); //移除节点
              this.$nextTick(() => {
                this.isDelete = false;
                this.jsplumb.ready(() => {
                  this.initAll();
                  // this.connectionAll();
                  this.switchContainer(true, true, true);
                });
              });
            },
          },
          {
            label: "复制",
            disabled: item.identifier !== "child", //开始结束不允许复制
            onClick: () => {
              let list = JSON.parse(JSON.stringify(item));
              list.x = item.x + 30;
              list.y = item.y + 30;
              list.id = `task_${parseInt(
                new Date().getTime() / 1000
              )}_${Math.ceil(Math.random() * 10)}`;
              console.log(item);
              this.mapList.push(list);
              this.$nextTick(() => {
                this.isDelete = false;
                this.jsplumb.ready(() => {
                  this.initAll();
                  // this.connectionAll();
                  this.switchContainer(true, true, true);
                });
              });
            },
          },
        ],
        event,
        customClass: "class-a",
        zIndex: 3,
        minWidth: 150,
      });
      return false;
    },

    //双击事件--打开弹窗
    dbBtn(item) {
      if (item.identifier === "child") {
        this.visibleList = {};
        this.visibleList = JSON.parse(JSON.stringify(item));
        this.drawer = true;
      } else {
        this.$message.error("您好，您当前点中的节点不是子组件，无法修改数据");
      }
    },

    //弹窗确定事件
    submitForm() {
      this.mapList.forEach((x) => {
        // this.$set(x,'name',)
        if (x.id == this.visibleList.id) {
          Object.assign(x, this.visibleList);
        }
      });
      this.drawer = false;
    },

    //鼠标移动来向vuex进行传值--查看数据
    mousemove() {
      let list = {
        mapList: this.mapList,
        connectList: this.connectList,
      };
      this.$store.commit("viewBtn", JSON.stringify(list));
    },
  },
  watch: {
    // 监听vuex的变化 当产生变化的时候 插入值
    "$store.state.mapList": {
      handler(newName) {
        console.log("执行");
        if (newName.id) {
          let list = this.mapList.map((x) => x.identifier);
          if (list.includes("start") && newName.identifier === "start") {
            this.$message.error("您好，只能拥有一个开始节点");
          } else if (list.includes("end") && newName.identifier === "end") {
            this.$message.error("您好，只能拥有一个结束节点");
          } else {
            this.mapList.push(newName);
            console.log("监听");
            console.log(this.connectList);
            this.$nextTick(() => {
              this.jsplumb.ready(() => {
                this.initAll();
                // this.connectionAll();
                this.switchContainer(true, true, true);
              });
            });
            console.log(this.mapList);
          }
        }
      },
      deep: true,
      immediate: true,
    },
  },
};
</script>

<style lang="scss" scoped>
#center {
  width: 100%;
  height: 100%;
  position: relative;
}
</style>

<style lang="scss">
#center {
  #drawer {
    .el-drawer__header {
      margin-bottom: 10px;
      color: black;
    }
    .el-form-item {
      padding: 0 20px;
      margin-bottom: 0;
      .el-form-item__label {
        padding: 0;
      }
    }
    #footer {
      display: flex;
      justify-content: flex-end;
      margin-top: 1rem;
    }
  }
}
.class-a {
  padding: 3px 0px !important;
  .menu_item {
    line-height: 30px !important;
  }
}
</style>
